.\" Copyright (c) 2004-2020 Julien Nadeau Carriere <vedge@csoft.net>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in the
.\"    documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
.\" (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 9, 2004
.Dt AG_TIMER 3
.Os
.ds vT Agar API Reference
.ds oS Agar 1.5
.Sh NAME
.Nm AG_Timer
.Nd agar timer facility
.Sh SYNOPSIS
.Bd -literal
#include <agar/core.h>
.Ed
.Sh DESCRIPTION
.\" MANLINK(AG_Timeout)
.\" MANLINK(AG_Timers)
The
.Nm
structure describes a unique timer, which may or may not be associated with
some parent
.Xr AG_Object 3 .
If a timer has a parent object, Agar will guarantee cancellation of any
callbacks if the parent object is destroyed or detached.
When a timer expires, its callback routine is executed.
Timer callback routines should be defined as:
.Pp
.nr nS 1
.Ft "Uint32"
.Fn AG_TimerFn "AG_Timer *timer" "AG_Event *event"
.Pp
.nr nS 0
The
.Fa timer
argument, and the list of arguments under
.Fa event
are those previously specified in
.Fn AG_AddTimer .
The current timer interval (in ticks) can be retrieved from the
.Va ival
member of the
.Nm
structure.
The callback should return a new timer interval (if the timer is
to be restarted), or 0 if the timer is to be cancelled.
.Pp
The timer's parent object is guaranteed to remain locked during the execution
of the callback.
The context of execution of the callback is platform-dependent.
On platforms where
.Xr kqueue 2
is available, the routine is executed in the event loop.
On platforms where only POSIX timers are available, the routine is
executed in a separate thread.
On platforms which don't provide any timer interface at all, the event
loop repeatedly calls
.Fn AG_ProcessTimeouts
routine to process expired timers.
Different objects may also manage timers differently (see
.Sx SPECIALIZED TIMERS
below).
.Sh INTERFACE
.nr nS 1
.Ft "void"
.Fn AG_InitTimer "AG_Timer *timer" "const char *name" "Uint flags"
.Pp
.Ft "int"
.Fn AG_AddTimer "void *obj" "AG_Timer *timer" "Uint32 t" "Uint32 (*fn)(AG_Timer *, AG_Event *)" "const char *fmt" "..."
.Pp
.Ft "AG_Timer *"
.Fn AG_AddTimerAuto "void *obj" "Uint32 t" "Uint32 (*fn)(AG_Timer *, AG_Event *)" "const char *fmt" "..."
.Pp
.Ft "void"
.Fn AG_DelTimer "void *obj" "AG_Timer *timer"
.Pp
.Ft "void"
.Fn AG_DelTimers "void *obj"
.Pp
.Ft "int"
.Fn AG_ResetTimer "void *obj" "AG_Timer *timer" "Uint32 t"
.Pp
.Ft "void"
.Fn AG_LockTimers "void *obj"
.Pp
.Ft "void"
.Fn AG_UnlockTimers "void *obj"
.Pp
.Ft "int"
.Fn AG_TimerIsRunning "void *obj" "AG_Timer *timer"
.Pp
.Ft "Uint32"
.Fn AG_ExecTimer "AG_Timer *timer"
.Pp
.Ft "void"
.Fn AG_ProcessTimeouts "Uint32 ticks"
.Pp
.nr nS 0
The
.Fn AG_InitTimer
routine initializes a
.Nm
structure.
.Fa name
is an optional string identifier, useful for debugging purposes.
Acceptable
.Fa flags
options include:
.Bl -tag -width "AG_TIMER_SURVIVE_DETACH "
.It Dv AG_TIMER_SURVIVE_DETACH
Don't automatically cancel the timer if its parent object is being
detached (see
.Xr AG_ObjectDetach 3 ) .
.It Dv AG_TIMER_AUTO_FREE
Automatically free() the timer structure upon expiration or cancellation
(set implicitely by
.Fn AG_AddTimerAuto ) .
.El
.Pp
The
.Fn AG_AddTimer
function starts the timer.
The optional
.Fa obj
argument specifies a parent
.Xr AG_Object 3
which will manage the timer.
The callback routine is specified as the
.Fn fn
argument.
Arguments to pass to the callback may be specified under
.Fa fmt
(using the
.Xr AG_Event 3
style of argument passing).
The
.Fn AG_AddTimer
function returns 0 on success or -1 if the timer could not be created.
.Pp
Timers created with
.Fn AG_AddTimer
are set to expire in
.Fa t
ticks from now.
On expiration, the timer's callback is invoked.
If it returns a non-zero number of ticks, the timer is restarted, otherwise
it is cancelled.
.Pp
The
.Fn AG_AddTimerAuto
variant of
.Fn AG_AddTimer
allocates an anonymous
.Ft AG_Timer
structure which will be freed upon cancellation.
On success, a pointer to the new timer structure is returned (it is not
safe to dereference this pointer unless
.Fn AG_LockTimers
is in effect).
On failure,
.Fn AG_AddTimerAuto
returns NULL.
.Pp
The
.Fn AG_DelTimer
function cancels the execution of a timer and frees all resources
allocated by it.
If the given timer is not active,
.Fn AG_DelTimer
does nothing.
The optional
.Fa obj
argument specifies the timer's parent object.
The
.Fa timer
argument does not need to point to an initialized structure.
If the timer is not running,
.Fn AG_DelTimer
is a safe no-op.
.Pp
The
.Fn AG_ResetTimer
function changes the interval of a running timer, such that it will expire
in
.Fa t
ticks from now.
It is illegal to invoke
.Fn AG_ResetTimer
on a timer that is not currently running, and the call must be protected by
.Fn AG_LockTimers .
.Pp
In the timer callback routine, it is safe to make
.Fn AG_AddTimer
or
.Fn AG_DelTimer
calls.
It is not safe to try and detach or destroy the timer's parent object from
the callback routine.
.Pp
The
.Fn AG_TimerIsRunning
function returns 1 if the timer is active.
For thread safety, the call should be protected by
.Fn AG_LockTimers :
.Bd -literal -offset indent
AG_LockTimers(obj);
if (AG_TimerIsRunning(obj, &timer)) {
	...
}
AG_UnlockTimers(obj);
.Ed
.Pp
.Fn AG_ExecTimer
runs the timer's callback routine artificially and returns its return value.
The caller is normally expected to use
.Fn AG_DelTimer
on a return value of 0 and
.Fn AG_ResetTimer
if the returned interval differs from current
.Va to->ival .
.Pp
The
.Fn AG_ProcessTimeouts
function advances the timing wheel and executes the callbacks of
expired timers.
Normally, this function is not used directly, but it can be useful on
platforms without timer interfaces (i.e.,
.Fn AG_ProcessTimeouts
may be called repeatedly from a delay loop).
The
.Fa ticks
argument is the monotonic time in ticks (usually obtained from
.Xr AG_GetTicks 3 ) .
For
.Fn AG_ProcessTimeouts
to work as expected, the
.Dv AG_SOFT_TIMERS
flag must be passed to
.Xr AG_InitCore 3 .
.Sh SPECIALIZED TIMERS
The
.Nm
interface is not tied to any specific time source.
A timer's parent object may influence the way timers are processed.
.Pp
By default, the execution of timers is based on the progress of a
monotonic system clock and one "tick" is roughly equivalent to one
millisecond.
However, it is possible for different parent objects to process time
differently.
For example, an object in a simulation application might manage its timers
using use some software-defined time, or an offline renderer might require
that logic time be stopped during rendering (see
.Xr AG_Time 3 ) .
.Sh SEE ALSO
.Xr AG_Event 3 ,
.Xr AG_GetTicks 3 ,
.Xr AG_Intro 3 ,
.Xr AG_Object 3 ,
.Xr AG_SchedEvent 3 ,
.Xr AG_Time 3
.Rs
.%T "Hashed and Hierarchical Timing Wheels: Efficient Data Structures for Implementing a Timer Facility"
.%A "George Varghese"
.%A "Tony Lauck"
.%D "February 14, 1996"
.Re
.Sh HISTORY
The
.Nm
facility first appeared in Agar 1.0 as
.Ft AG_Timeout ,
and was modeled after the OpenBSD
.Xr timeout 9
API by Artur Grabowski and Thomas Nordin.
In Agar 1.5.0, callback routines were allowed to accept multiple arguments,
and support for
.Xr kqueue 2
was added.
